﻿namespace MicroCloud.Authorization
{
    /// <summary>
    /// 模块信息提取器基类
    /// </summary>
    public abstract class ModuleInfoPickerBase<TFunction> : IModuleInfoPicker
        where TFunction : class, IEntity<long>, IFunction, new()
    {
        /// <summary>
        /// 初始化一个模块信息提取器基类 <see cref="ModuleInfoPickerBase{TFunction}"/> 的新实例
        /// </summary>
        /// <param name="serviceProvider">服务提供者</param>
        protected ModuleInfoPickerBase(IServiceProvider serviceProvider)
        {
            Logger = serviceProvider.GetLogger(GetType());
            FunctionHandler = serviceProvider.GetService<IFunctionHandler>();
        }

        #region 属性
        /// <summary>
        /// 获取 日志记录对象
        /// </summary>
        protected ILogger Logger { get; }
        
        /// <summary>
        /// 获取 功能处理器
        /// </summary>
        protected IFunctionHandler FunctionHandler { get; }

        #endregion

        #region 方法
        /// <summary>
        /// 从程序集中获取模块信息
        /// </summary>
        public ModuleInfo[] Pickup()
        {
            //Logger.LogInformation("开始提取模块(Module)信息");
            Check.NotNull(FunctionHandler, nameof(FunctionHandler));
            Type[] moduleTypes = FunctionHandler.GetAllFunctionTypes().Where(type => type.HasAttribute<ModuleInfoAttribute>()).ToArray();
            ModuleInfo[] modules = GetModules(moduleTypes);
            Logger.LogInformation("从程序集中提取到 {length} 个模块(Module)信息", modules.Length);
            return modules;
        }

        #endregion

        #region 受保护的方法
        /// <summary>
        /// 重写以实现从类型中提取模块信息
        /// </summary>
        /// <param name="moduleTypes"></param>
        /// <returns></returns>
        protected virtual ModuleInfo[] GetModules(Type[] moduleTypes)
        {
            List<ModuleInfo> infos = new();
            foreach (Type moduleType in moduleTypes)
            {
                string[] existPaths = infos.Select(m => $"{m.Position}.{m.Code}").ToArray();
                ModuleInfo[] typeInfos = GetModules(moduleType, existPaths);
                foreach (ModuleInfo info in typeInfos)
                {
                    if (info.OrderNo.Equals(0))
                    {
                        info.OrderNo = infos.Count(m => m.Position == info.Position) + 1;
                    }
                    if (!infos.Contains(info))
                    {
                        infos.Add(info);
                        Logger.LogDebug("提取模块信息：{name}[{code}]({position})，包含共计 {length} 个功能。", info.Name, info.Code, info.Position, info.DependOnFunctions.Length);
                    }
                }

                MethodInfo[] methods = FunctionHandler.GetMethodInfos(moduleType).Where(type => type.HasAttribute<ModuleInfoAttribute>()).ToArray();
                for (int index = 0; index < methods.Length; index++)
                {
                    ModuleInfo info = GetModule(methods[index], typeInfos.Last(), index);
                    if (info != null)
                    {
                        infos.Add(info);
                        Logger.LogDebug("提取模块信息：{name}[{code}]({position})，包含共计 {length} 个功能。", info.Name, info.Code, info.Position, info.DependOnFunctions.Length);
                    }
                }
            }

            return infos.ToArray();
        }

        #endregion

        #region 抽象方法
        /// <summary>
        /// 重写以实现从类型中提取模块信息
        /// </summary>
        /// <param name="type">类型信息</param>
        /// <param name="existPaths">已存在的路径集合</param>
        /// <returns>提取到的模块信息</returns>
        protected abstract ModuleInfo[] GetModules(Type type, string[] existPaths);
        
        /// <summary>
        /// 重写以实现从方法信息中提取模块信息
        /// </summary>
        /// <param name="method">方法信息</param>
        /// <param name="typeInfo">所在类型模块信息</param>
        /// <param name="index">序号</param>
        /// <returns>提取到的模块信息</returns>
        protected abstract ModuleInfo GetModule(MethodInfo method, ModuleInfo typeInfo, int index);

        #endregion

    }

}
